package com.walming.generator.support.controller;

import com.alibaba.fastjson.JSON;
import com.walming.generator.common.constant.Constants;
import com.walming.generator.common.core.controller.BaseController;
import com.walming.generator.common.core.domain.AjaxResult;
import com.walming.generator.common.core.domain.CxSelect;
import com.walming.generator.common.core.page.TableDataInfo;
import com.walming.generator.common.exception.DemoModeException;
import com.walming.generator.common.utils.StringUtils;
import com.walming.generator.common.utils.text.Convert;
import com.walming.generator.support.domain.GenTable;
import com.walming.generator.support.domain.GenTableColumn;
import com.walming.generator.support.domain.SysDataSource;
import com.walming.generator.support.query.GenTableQuery;
import com.walming.generator.support.service.IGenTableColumnService;
import com.walming.generator.support.service.IGenTableService;
import com.walming.generator.support.service.ISysDataSourceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 代码生成操作处理
 *
 * @author walming
 */
@Controller
@RequestMapping("/tool/gen")
@Api(value = "代码生成操作处理", tags = "代码生成操作处理")
public class GenController extends BaseController {

    private static final String PREFIX = "tool/gen";

    @Resource
    private IGenTableService genTableService;
    @Resource
    private ISysDataSourceService sysDataSourceService;
    @Resource
    private IGenTableColumnService genTableColumnService;

    /**
     * 代码生成列表界面
     */
    @GetMapping()
    public String gen(ModelMap modelMap) {
        List<SysDataSource> dataSourceList = sysDataSourceService.list();
        modelMap.put("dataSourceList", dataSourceList);
        return PREFIX + "/gen";
    }

    /**
     * 根据业务表id生成预览代码信息并进入界面展示
     */
    @GetMapping("/preview/{tableId}")
    @ApiOperation(value = "根据业务表id生成预览代码信息并进入界面", notes = "根据业务表id生成预览代码信息并进入界面")
    public String preview(@PathVariable("tableId") Long tableId, ModelMap modelMap) {
        modelMap.put("previewCode", genTableService.previewCode(tableId));
        return PREFIX + "/preview";
    }

    /**
     * 根据业务表id生成预览代码对外API
     */
    @ResponseBody
    @GetMapping("/previewCode/{tableId}")
    @ApiOperation(value = "根据业务表id生成预览代码", notes = "根据业务表id生成预览代码")
    public AjaxResult<Map<String, String>> previewCode(@PathVariable("tableId") Long tableId) {
        Map<String, String> dataMap = genTableService.previewCode(tableId);
        return AjaxResult.success(dataMap);
    }

    /**
     * 分页条件查询获取业务表结构
     *
     * @param tableQuery 查询参数
     * @return 列表
     */
    @ResponseBody
    @PostMapping("/list")
    @ApiOperation(value = "分页条件查询获取业务表结构", notes = "分页条件查询获取业务表结构")
    public TableDataInfo<GenTable> genList(GenTableQuery tableQuery) {
        return toPageResult(genTableService.startPage(tableQuery));
    }

    /**
     * 查询数据库列表
     */
    @ResponseBody
    @PostMapping("/db/list")
    @ApiOperation(value = "查询数据库列表", notes = "查询数据库列表")
    public TableDataInfo<GenTable> dataList(GenTableQuery tableQuery) {
        startPage();
        List<GenTable> list = genTableService.selectDbTableList(tableQuery);
        return toPageResult(list);
    }

    /**
     * 查询数据表字段列表
     */
    @ResponseBody
    @PostMapping("/column/list")
    @ApiOperation(value = "查询数据表字段列表", notes = "查询数据表字段列表")
    public TableDataInfo<GenTableColumn> columnList(GenTableColumn genTableColumn) {
        TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn.getTableId());
        dataInfo.setRows(list);
        dataInfo.setTotal(list.size());
        return dataInfo;
    }

    /**
     * 导入表结构
     */
    @GetMapping("/importTable/{dataSourceId}")
    public String importTable(@PathVariable("dataSourceId") Long id, ModelMap modelMap) {
        modelMap.put("dataSourceId", id);
        return PREFIX + "/importTable";
    }

    /**
     * 根据表名与数据源批量导入表结构（多个用逗号分隔）
     */
    @ResponseBody
    @PostMapping("/importTable")
    @ApiOperation(value = "根据表名与数据源批量导入表结构", notes = "根据表名与数据源批量导入表结构")
    public AjaxResult<Object> importTableSave(String tables, Long dataSourceId) {
        String[] tableNames = Convert.toStrArray(tables);
        // 查询表信息
        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames, dataSourceId);
        genTableService.importGenTable(tableList, dataSourceId);
        return AjaxResult.success();
    }

    /**
     * 修改代码生成业务
     */
    @GetMapping("/edit/{tableId}")
    public String edit(@PathVariable("tableId") Long tableId, ModelMap modelMap) {
        GenTable table = genTableService.selectGenTableById(tableId);
        List<GenTable> genTables = genTableService.selectGenTableAll(table.getDataSourceId());
        List<CxSelect> cxSelect = new ArrayList<>();
        for (GenTable genTable : genTables) {
            if (!StringUtils.equals(table.getTableName(), genTable.getTableName())) {
                CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + '：' + genTable.getTableComment());
                List<CxSelect> cxColumns = new ArrayList<>();
                for (GenTableColumn tableColumn : genTable.getColumns()) {
                    cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + '：' + tableColumn.getColumnComment()));
                }
                cxTable.setS(cxColumns);
                cxSelect.add(cxTable);
            }
        }
        modelMap.put("table", table);
        modelMap.put("data", JSON.toJSON(cxSelect));
        return PREFIX + "/edit";
    }

    /**
     * 修改保存代码生成业务
     */
    @ResponseBody
    @PostMapping("/edit")
    @ApiOperation(value = "修改保存代码生成业务", notes = "修改保存代码生成业务")
    public AjaxResult<Object> editSave(@Validated GenTable genTable) {
        if (Constants.DEMO_TAG.equals(genTable.getTableId())) {
            throw new DemoModeException();
        }
        genTableService.validateEdit(genTable);
        genTableService.updateGenTable(genTable);
        return AjaxResult.success();
    }

    /**
     * 根据id删除业务表数据（多个用逗号分隔）
     *
     * @param ids ids
     * @return 结果
     */
    @ResponseBody
    @PostMapping("/remove")
    @ApiOperation(value = "根据id删除业务表数据（多个用逗号分隔）", notes = "根据id删除业务表数据（多个用逗号分隔）")
    public AjaxResult<Object> remove(String ids) {
        List<Long> list = Arrays.asList(Convert.toLongArray(ids));
        if (list.contains(Constants.DEMO_TAG)) {
            throw new DemoModeException();
        }
        genTableService.deleteGenTableByIds(list);
        return AjaxResult.success();
    }

    /**
     * 生成代码（下载方式）
     */
    @GetMapping("/download/{tableName}")
    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException {
        byte[] data = genTableService.downloadCode(tableName);
        genCode(response, data);
    }

    /**
     * 生成代码（自定义路径）
     */
    @ResponseBody
    @GetMapping("/genCode/{tableName}")
    public AjaxResult<Object> genCode(@PathVariable("tableName") String tableName) {
        genTableService.generatorCode(tableName);
        return AjaxResult.success();
    }

    /**
     * 从数据库同步更新表结构
     */
    @ResponseBody
    @GetMapping("/synchDb/{tableName}/{tableId}")
    @ApiOperation(value = "同步数据库", notes = "同步数据库")
    public AjaxResult<Object> synchDb(@PathVariable("tableName") String tableName, @PathVariable("tableId") Long tableId) {
        genTableService.syncDb(tableName, tableId);
        return AjaxResult.success();
    }

    /**
     * 批量生成代码
     */
    @ResponseBody
    @GetMapping("/batchGenCode")
    public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
        String[] tableNames = Convert.toStrArray(tables);
        byte[] data = genTableService.downloadCode(tableNames);
        genCode(response, data);
    }

    /**
     * 生成zip文件
     */
    private void genCode(HttpServletResponse response, byte[] data) throws IOException {
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"code.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(data, response.getOutputStream());
    }

}